package util

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/des"
)

// des的CBC加密
// 编写填充函数, 如果最后一个分组字节数不够, 填充
// ......字节数刚好合适, 添加一个新的分组
// 填充个的字节的值 == 缺少的字节的数
func paddingLastGroup(plainText []byte, bloclSize int) []byte {
	//要填充的字节数
	padNum := bloclSize - len(plainText)%bloclSize
	//要填充的单字节
	byOne := byte(padNum)
	//要填充的完整切片
	newAddPlainText := bytes.Repeat([]byte{byOne}, padNum)
	//追加明文后面再返回
	return append(plainText, newAddPlainText...)
}

// 去掉明文的填充
func unPaddingLastGrooup(plainText []byte) []byte {
	i := len(plainText)
	padNum := int(plainText[i-1])
	//截取除尾部的,返回剩余部分的
	return plainText[:i-padNum]
}

// des加密
func DesEncrypt(plainText, key []byte, iv []byte) []byte {
	block, err := des.NewCipher(key)
	if err != nil {
		panic(err)
	}
	//填充
	plainText = paddingLastGroup(plainText, block.BlockSize())
	//密码模式
	blockMode := cipher.NewCBCEncrypter(block, iv[:block.BlockSize()])
	cipherText := make([]byte, len(plainText))
	blockMode.CryptBlocks(cipherText, plainText)
	//blockMode.CryptBlocks(plainText, plainText) //会覆盖
	return cipherText
}

// des 解密
func DesDecrypt(cipherText, key []byte, iv []byte) []byte {
	block, err := des.NewCipher(key)
	if err != nil {
		panic(err)
	}
	cipher.NewCBCDecrypter(block, iv[:block.BlockSize()]).CryptBlocks(cipherText, cipherText)
	return unPaddingLastGrooup(cipherText)
}

// aes加密
func AesEncrypt(plainText, key []byte, iv []byte) []byte {
	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}
	//密码模式
	stream := cipher.NewCTR(block, iv[:block.BlockSize()])
	cipherText := make([]byte, len(plainText))
	stream.XORKeyStream(cipherText, plainText)
	//blockMode.CryptBlocks(plainText, plainText) //会覆盖
	return cipherText
}

// aes 解密
func AesDecrypt(cipherText, key []byte, iv []byte) []byte {
	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}
	cipher.NewCTR(block, iv[:block.BlockSize()]).XORKeyStream(cipherText, cipherText)
	return cipherText
}
